@********************************************************************
@*          intr_main.s                                             *
@*            Interrupt Branch Routine (GAS)                        *
@*                                                                  *
@*          Copyright (C) 1999-2001 NINTENDO Co.,Ltd.               *
@********************************************************************
    .INCLUDE    "AgbDefine.s"
    .INCLUDE    "AgbMemoryMap.s"
    .INCLUDE    "AgbSyscallDefine.s"
    .INCLUDE    "AgbMacro.s"
    .TEXT

    .INCLUDE    "MultiSioDefine.s"

@--------------------------------------------------------------------
@-Interrupt Branch Processing(Multiple Interrupts)(Lookup Table)42-80c -
@--------------------------------------------------------------------
    .EXTERN     IntrTableBuf
    .GLOBAL     intr_main
    .ALIGN
    .CODE 32
intr_main:
        mov     r3, #REG_BASE           @ IE/IF Read
        add     r3, r3, #OFFSET_REG_IE  @ r3:  REG_IE
        ldr     r12, [r3]               @ r12: IF|IE

        mrs     r0, spsr                @ Save register (IRQ Mode)
        stmfd   sp!, {r0, r3, r12, lr}  @ {spsr, REG_IE, IF|IE, lr}

        and     r1, r12, r12, lsr #16   @ IE/IF Check
        mov     r2, #0
        ands    r0, r1, #SIO_INTR_FLAG | MULTI_SIO_TIMER_INTR_FLAG
        bne     jump_intr                    @ Serial Communication Interrupt  
        add     r2, r2, #4                   @ or multi-play communication timer interrupt

        ands    r0, r1, #V_BLANK_INTR_FLAG   @ V-Blank Interrupt
        bne     jump_intr
        add     r2, r2, #4

        ands    r0, r1, #H_BLANK_INTR_FLAG   @ H-Blank Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #V_COUNT_INTR_FLAG   @ V Counter Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA0_INTR_FLAG      @ DMA0 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA1_INTR_FLAG      @ DMA1 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA2_INTR_FLAG      @ DMA2 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #DMA3_INTR_FLAG      @ DMA3 Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #KEY_INTR_FLAG       @ Key Interrupt
        bne     jump_intr
        add     r2, r2, #4
        ands    r0, r1, #CASSETTE_INTR_FLAG  @ Game Pak Interrupt
loop:   bne     loop
jump_intr:
        strh    r0, [r3, #2]                    @ Clear IF       23c
                                                    @ Set IE <- Select multiple interrupts
        ldr     r1, =CASSETTE_INTR_FLAG | SIO_INTR_FLAG | MULTI_SIO_TIMER_INTR_FLAG
        and     r1, r1, r12
        strh    r1, [r3]
        mrs     r3, cpsr                            @ Enable multiple interrupts & switch to system mode
        bic     r3, r3, #PSR_CPU_MODE_MASK | PSR_IRQ_DISABLE | PSR_FIQ_DISABLE
        orr     r3, r3, #PSR_SYS_MODE
        msr     cpsr, r3
@---------------------------------------------------------------------System Mode
        ldr     r1, =IntrTableBuf                   @ Jump to User IRQ Processing
        add     r1, r1, r2
        ldr     r0, [r1]

        stmfd   sp!, {lr}                           @ Save Register (system mode)
        adr     lr, intr_return                     @ Set Return Address
        bx      r0
intr_return:
        ldmfd   sp!, {lr}                           @ Return to register (system mode)

        mrs     r3, cpsr                            @ Disable multiple interrupts & switch to IRQ mode
        bic     r3, r3, #PSR_CPU_MODE_MASK | PSR_IRQ_DISABLE | PSR_FIQ_DISABLE
        orr     r3, r3, #PSR_IRQ_MODE      | PSR_IRQ_DISABLE
        msr     cpsr, r3
@---------------------------------------------------------------------IRQ Mode
        ldmfd   sp!, {r0, r3, r12, lr}          @ Return to register (IRQ mode)
        strh    r12, [r3]                       @ {spsr, REG_IE, IF|IE, lr}
        msr     spsr, r0
        bx      lr                              @ Return to before interrupt


    .END

